/*
 * Copyright (C) 2018 Zhejiang lishiots Technology CO.,LTD.
 * All rights reserved.
 * Official Web Site: http://www.lishiots.com.
 * Developer Web Site: http://open.lishiots.com.
 */

package com.xiaominfo.oss.sdk;

import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import com.xiaominfo.oss.sdk.client.FileBytesRequest;
import com.xiaominfo.oss.sdk.client.FileBytesResponse;
import com.xiaominfo.oss.sdk.common.OSSClientMessage;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/***
 *
 * @since:oss-server 1.0
 * @author <a href="mailto:xiaoymin@foxmail.com">xiaoymin@foxmail.com</a> 
 * 2018/05/30 17:00
 */
public class OSSClient {

    /***
     * byte64 上传
     */
    private static final String v1_upload_file_binary_api="/oss/material/uploadByBinary";

    /***
     * form表单上传
     */
    private static final String UPLOAD_FILE_FORM_API="/oss/material/uploadMaterialNonProUrl";



    private OSSClientProperty ossClientProperty;

    public OSSClient(OSSClientProperty ossClientProperty) {
        this.ossClientProperty = ossClientProperty;
        //初始化上传url地址
        if (ossClientProperty!=null&&ossClientProperty.getRemote()!=null&&!"".equalsIgnoreCase(ossClientProperty.getRemote())){
            StringBuffer endpoint=new StringBuffer();
            endpoint.append(ossClientProperty.getRemote());
            if (ossClientProperty.getRemote().endsWith("/")){
                endpoint.append(UPLOAD_FILE_FORM_API.substring(1));
            }else{
                endpoint.append(UPLOAD_FILE_FORM_API);
            }
            this.ossClientProperty.setRemote(endpoint.toString());
        }
    }

    /***
     * 设置默认header
     * @param request
     */
    private void addDefaultHeader(HttpUriRequest request){
        request.addHeader("Content-Encoding","gzip");
        request.addHeader("Content-type", "application/json");
    }

    private void handleServerExceptionMessage(OSSClientMessage ossClientMessage,Exception e){
        ossClientMessage.setCode("8500");
        ossClientMessage.setMessage(e.getMessage());
    }

    /***
     * 创建数组
     * @param fileBytesRequests
     * @return
     */
    private JsonArray createFileArrs(List<FileBytesRequest> fileBytesRequests){
        JsonArray jsonArray=new JsonArray();
        for (FileBytesRequest fileBytesRequest:fileBytesRequests){
            JsonObject fileObj=new JsonObject();
            fileObj.addProperty("media_type",fileBytesRequest.getMediaType());
            fileObj.addProperty("file",fileBytesRequest.getFile());
            fileObj.addProperty("original_name",fileBytesRequest.getOriginalName());
            jsonArray.add(fileObj);
        }
        return jsonArray;
    }

    /**
     * 创建请求参数
     * @param fileBytesRequests
     * @param project
     * @return
     */
    private JsonObject createRequestParams(List<FileBytesRequest> fileBytesRequests,String project){
        JsonObject param=new JsonObject();
        param.addProperty("project",project);
        param.addProperty("appid",ossClientProperty.getAppid());
        param.addProperty("appsecret",ossClientProperty.getAppsecret());
        param.add("files",createFileArrs(fileBytesRequests));
        return param;
    }

    private void addRequestParam(HttpPost request,List<FileBytesRequest> fileBytesRequests,String project){
        JsonObject param=createRequestParams(fileBytesRequests,ossClientProperty.getProject());
        request.setEntity(new StringEntity(param.toString(),"UTF-8"));
    }


    /***
     * 处理结果
     * @param closeableHttpResponse
     * @param ossClientMessage
     * @param type
     * @throws IOException
     */
    private void handleResult(CloseableHttpResponse closeableHttpResponse,OSSClientMessage ossClientMessage,Type type) throws IOException {
        if (closeableHttpResponse.getStatusLine().getStatusCode()== HttpStatus.SC_OK) {
            String content = EntityUtils.toString(closeableHttpResponse.getEntity(), "UTF-8");
            if (content != null && !"".equals(content)) {
                JsonElement jsonE = new JsonParser().parse(content);
                ossClientMessage.setCode(jsonE.getAsJsonObject().get("code").getAsString());
                ossClientMessage.setMessage(jsonE.getAsJsonObject().get("message").getAsString());
                JsonElement data=jsonE.getAsJsonObject().get("data");
                ossClientMessage.setData(new Gson().fromJson(data,type));
            }
        }
    }

    /***
     * 文件上传
     * @param file
     * @return
     */
    public OSSClientMessage<FileBytesResponse> uploadFile(File file){
        OSSClientMessage<FileBytesResponse> ossClientMessage=new OSSClientMessage<>();
        try{
            if (file.isDirectory()){
                //文件不能是目录
                throw new RuntimeException("file can't be directory ");
            }
            //获取文件原始名称
            String originalName=file.getName();
            String mediaType="unkown";
            int idx=originalName.lastIndexOf(".");
            if (idx>0){
                mediaType=originalName.substring(idx+1);
            }
            String filebyteString= Base64.encodeBase64String(FileUtils.readFileToByteArray(file));
            FileBytesRequest fileBytesRequest=new FileBytesRequest();
            fileBytesRequest.setFile(filebyteString);
            fileBytesRequest.setMediaType(mediaType);
            fileBytesRequest.setOriginalName(originalName);
            ossClientMessage=uploadFileByte(fileBytesRequest);
        }catch (Exception e){
            handleServerExceptionMessage(ossClientMessage,e);
        }
        return ossClientMessage;
    }

    /***
     * 批量上传文件
     * @param uploadFiles
     * @return
     */
    public OSSClientMessage<List<FileBytesResponse>> uploadFiles(List<File> uploadFiles){
        OSSClientMessage<List<FileBytesResponse>> ossClientMessage=new OSSClientMessage<>();
        try{
            List<FileBytesRequest> fileBytesRequests=new ArrayList<>();
            for (File file:uploadFiles){
                if (file.isDirectory()){
                    //文件不能是目录
                    throw new RuntimeException("file {"+file.getName()+"} can't be directory ");
                }
            }
            for (File file:uploadFiles){
                //获取文件原始名称
                String originalName=file.getName();
                String mediaType="unkown";
                int idx=originalName.lastIndexOf(".");
                if (idx>0){
                    mediaType=originalName.substring(idx+1);
                }
                String filebyteString= Base64.encodeBase64String(FileUtils.readFileToByteArray(file));
                FileBytesRequest fileBytesRequest=new FileBytesRequest();
                fileBytesRequest.setFile(filebyteString);
                fileBytesRequest.setMediaType(mediaType);
                fileBytesRequest.setOriginalName(originalName);
                fileBytesRequests.add(fileBytesRequest);
            }
            ossClientMessage=uploadFilesByte(fileBytesRequests);
        }catch (Exception e){
            handleServerExceptionMessage(ossClientMessage,e);
        }
        return ossClientMessage;
    }

    /***
     * 字节字符串形式上传文件
     * @param fileBytesRequest
     * @return
     */
    public OSSClientMessage<FileBytesResponse> uploadFileByte(FileBytesRequest fileBytesRequest){
        OSSClientMessage<FileBytesResponse> ossClientMessage=new OSSClientMessage<>();
        CloseableHttpResponse closeableHttpResponse=null;
        CloseableHttpClient httpClient=null;
        try{
            HttpPost request=new HttpPost(ossClientProperty.getRemote());
            addDefaultHeader(request);
            httpClient=HttpClients.createDefault();
            List<FileBytesRequest> fileBytesRequests=new ArrayList<>();
            fileBytesRequests.add(fileBytesRequest);
            addRequestParam(request,fileBytesRequests,ossClientProperty.getProject());
            closeableHttpResponse=httpClient.execute(request);
            if (closeableHttpResponse.getStatusLine().getStatusCode()== HttpStatus.SC_OK){
                String content= EntityUtils.toString(closeableHttpResponse.getEntity(),"UTF-8");
                if (content!=null&&!"".equals(content)){
                    JsonElement jsonE=new JsonParser().parse(content);
                    ossClientMessage.setCode(jsonE.getAsJsonObject().get("code").getAsString());
                    ossClientMessage.setMessage(jsonE.getAsJsonObject().get("message").getAsString());
                    Type type=new TypeToken<List<FileBytesResponse>>(){}.getType();
                    List<FileBytesResponse> fileBytesResponse=new Gson().fromJson(jsonE.getAsJsonObject().get("data"),type);
                    if (fileBytesResponse!=null&&fileBytesResponse.size()>0){
                        ossClientMessage.setData(fileBytesResponse.get(0));
                    }
                }
            }
        }catch (Exception e){
            handleServerExceptionMessage(ossClientMessage,e);
        }
        return ossClientMessage;
    }


    /***
     * form表单提交
     * @param file
     * @return
     */
    public OSSClientMessage<FileBytesResponse> uploadFileByForm(File file){
        OSSClientMessage<FileBytesResponse> ossClientMessage=new OSSClientMessage<>();
        CloseableHttpResponse closeableHttpResponse=null;
        CloseableHttpClient httpClient=null;
        try {
            HttpPost request = new HttpPost(ossClientProperty.getRemote());
            httpClient=HttpClients.createDefault();
            MultipartEntityBuilder builder= MultipartEntityBuilder.create();
            //表单参数
            builder.addPart("appid",new StringBody(ossClientProperty.getAppid(), ContentType.MULTIPART_FORM_DATA));
            builder.addPart("appsecret",new StringBody(ossClientProperty.getAppsecret(), ContentType.MULTIPART_FORM_DATA));
            builder.addPart("project",new StringBody(ossClientProperty.getProject(), ContentType.MULTIPART_FORM_DATA));
            //添加文件
            builder.addPart("file",new FileBody(file));
            //参数赋值
            request.setEntity(builder.build());
            closeableHttpResponse=httpClient.execute(request);
            if (closeableHttpResponse.getStatusLine().getStatusCode()== HttpStatus.SC_OK){
                String content= EntityUtils.toString(closeableHttpResponse.getEntity(),"UTF-8");
                if (content!=null&&!"".equals(content)){
                    JsonElement jsonE=new JsonParser().parse(content);
                    ossClientMessage.setCode(jsonE.getAsJsonObject().get("code").getAsString());
                    ossClientMessage.setMessage(jsonE.getAsJsonObject().get("message").getAsString());
                    Type type=new TypeToken<List<FileBytesResponse>>(){}.getType();
                    List<FileBytesResponse> fileBytesResponse=new Gson().fromJson(jsonE.getAsJsonObject().get("data"),type);
                    if (fileBytesResponse!=null&&fileBytesResponse.size()>0){
                        ossClientMessage.setData(fileBytesResponse.get(0));
                    }
                }
            }
        }catch (Exception e){
            handleServerExceptionMessage(ossClientMessage,e);
        }
        return ossClientMessage;
    }


    /**
     * 批量上传文件
     * @param fileBytesRequests
     * @return
     */
    public OSSClientMessage<List<FileBytesResponse>> uploadFilesByte(List<FileBytesRequest> fileBytesRequests){
        OSSClientMessage<List<FileBytesResponse>> ossClientMessage=new OSSClientMessage<>();
        CloseableHttpResponse closeableHttpResponse=null;
        CloseableHttpClient httpClient=null;
        try{
            HttpPost request=new HttpPost(ossClientProperty.getRemote());
            addDefaultHeader(request);
            httpClient=HttpClients.createDefault();
            addRequestParam(request,fileBytesRequests,ossClientProperty.getProject());
            closeableHttpResponse=httpClient.execute(request);
            if (closeableHttpResponse.getStatusLine().getStatusCode()== HttpStatus.SC_OK){
                String content= EntityUtils.toString(closeableHttpResponse.getEntity(),"UTF-8");
                if (content!=null&&!"".equals(content)){
                    JsonElement jsonE=new JsonParser().parse(content);
                    ossClientMessage.setCode(jsonE.getAsJsonObject().get("code").getAsString());
                    ossClientMessage.setMessage(jsonE.getAsJsonObject().get("message").getAsString());
                    Type type=new TypeToken<List<FileBytesResponse>>(){}.getType();
                    List<FileBytesResponse> fileBytesResponse=new Gson().fromJson(jsonE.getAsJsonObject().get("data"),type);
                    if (fileBytesResponse!=null&&fileBytesResponse.size()>0){
                        ossClientMessage.setData(fileBytesResponse);
                    }
                }
            }
        }catch (Exception e){
            handleServerExceptionMessage(ossClientMessage,e);
        }
        return ossClientMessage;
    }




    public static void main(String[] args) throws IOException {
        //客户端上传
        String url="http://192.168.0.6:18000/oss/material/uploadByBinary";
        OSSClientProperty ossClientProperty=new OSSClientProperty(url,"province_IIII");
        OSSClient ossClient=new OSSClient(ossClientProperty);
        File uploadFile=new File("C:\\Users\\xiaoymin\\Desktop\\aa.jpg");
        Gson gson=new Gson();
        OSSClientMessage<FileBytesResponse> ossClientMessage=ossClient.uploadFile(uploadFile);
        System.out.println(gson.toJson(ossClientMessage));

        /*System.out.println(uploadFile.getName());
        //获取文件原始名称
        String originalName=uploadFile.getName();
        String mediaType="unkown";
        int idx=originalName.lastIndexOf(".");
        if (idx>0){
            mediaType=originalName.substring(idx+1);
        }
        System.out.println(mediaType);
        String filebyteString= Base64.encodeBase64String(FileUtils.readFileToByteArray(uploadFile));
        CloseableHttpClient closeableHttpClient= HttpClients.createDefault();
        JsonObject fileObj=new JsonObject();
        fileObj.addProperty("media_type","png");
        fileObj.addProperty("file",filebyteString);
        fileObj.addProperty("original_name","test.png");
        JsonArray jsonArray=new JsonArray();
        jsonArray.add(fileObj);
        JsonObject param=new JsonObject();
        param.addProperty("project","province_III");
        param.add("files",jsonArray);

        request.addHeader("Content-Encoding","gzip");
        request.addHeader("Content-type", "application/json");
        request.setEntity(new StringEntity(param.toString(),"UTF-8"));

        CloseableHttpResponse response=closeableHttpClient.execute(request);
        if (response.getStatusLine().getStatusCode()== HttpStatus.SC_OK){
            String content= EntityUtils.toString(response.getEntity(),"UTF-8");
            System.out.println(content);
        }*/
















    }
}
